Release 10.1A: OpenEdge Development:
Progress 4GL Handbook


Running a procedure PERSISTENT

For all these reasons, Progress lets you run a procedure so that it stays in memory for as long as you need it, without it being dependent on, or in any way subordinate to, the procedure that runs it. A procedure run in this way is called a persistent procedure. You use this syntax to run it:

RUN procedure-name PERSISTENT [ SET proc-handle ] [ ( parameters )]. 

The PERSISTENT keyword in the statement tells Progress to start the procedure and to leave it in memory, either until you delete it or until your session ends.

Optionally, you can use the SET phrase to save off the handle of the new procedure. You’ve seen handle variables already. Of particular significance is that persistent procedures have handles the same as other objects do, so that you can access them after they’ve been instantiated by a RUN PERSISTENT statement. In fact, even a procedure that you run without the PERSISTENT option has a handle, but you would rarely use it. As noted above, the calling procedure can’t really execute any code until the procedure it runs terminates, and when that happens the subprocedure’s handle goes away, so the calling procedure would never really have a chance to use it.

In practice, you will almost always use the SET proc-handle option, because the way you make use of a persistent procedure is to initiate it with a RUN statement and then to use its handle afterwards to run entry points inside it. The proc-handle must be a variable or temp-table field with the HANDLE data type, defined or accessible in the calling procedure.

THIS-PROCEDURE built-in function

Whenever you run a procedure, persistent or not, you can retrieve its procedure handle using the built-in function THIS-PROCEDURE. This is useful when you want to access attributes or methods of the current procedure. There are some examples of this later in the "Useful procedure attributes and methods" section.

In most cases, you use procedure handles and the THIS-PROCEDURE function when you run persistent procedures. However, keep in mind that every running procedure, whether it is persistent or not, has a procedure handle that is held in THIS-PROCEDURE. A non-persistent procedure can pass THIS-PROCEDURE as an INPUT parameter to anther procedure, and the subprocedure can use that value to access internal procedures and other elements of the parent procedure. This is definitely not the norm for programming with procedure handles, but you can use it as a way to pass procedures down through a call stack, as the following example shows. This parent procedure passes its own procedure handle to another procedure as a parameter:

/* Procedure parentproc.p -- this runs another procedure and passes in its 
   own procedure handle. */ 
   RUN childproc.p (INPUT THIS-PROCEDURE). 
   PROCEDURE parentInternal: 
       DEFINE INPUT  PARAMETER cString AS CHARACTER   NO-UNDO. 
       MESSAGE "The child sent the parent " cString VIEW-AS ALERT-BOX. 
   END PROCEDURE. 

The child procedure can then use the parent’s handle to run the internal procedure in the parent:

/* childproc.p -- called from parentproc.p, it turns around and uses 
   the parent's procedure handle to run an internal procedure inside it. */ 
   DEFINE INPUT  PARAMETER hParent AS HANDLE     NO-UNDO. 
   RUN parentInternal IN hParent (INPUT "this child message"). 

The message shown in Figure 13–3 results.

Figure 13–3: Message result of childproc.p

This technique has limited usefulness, because there is no way for the parent to access internal procedures or other elements of the child procedure it runs. Only the child can access the parent procedures’s information.

Instantiating the persistent procedure

What happens when you run a procedure PERSISTENT? You already know that a procedure has a main block, which has all the code and definitions that are scoped to the procedure itself. Another way of saying this is that this is everything in the procedure file that isn’t in an internal procedure or a trigger. When you run a procedure PERSISTENT, its main block executes and then returns to the caller, just as it would without the PERSISTENT keyword. The difference is that when you run it PERSISTENT, the procedure stays in memory so that you can run internal procedures in it later on. The diagram in Figure 13–4 shows how this works.

Figure 13–4: Instantiating a persistent procedure

The code in Figure 13–4 executes as follows:

  1. MainProc.p RUNs SubProc.p PERSISTENT and saves off its procedure handle in the hProc variable. The main block of SubProc.p defines a variable and then executes the startup code represented by the DO this and DO that statements.
  2. The instantiation of the persistent procedure SubProc.p is complete. It returns control to MainProc.p, passing back through the SET phrase the procedure handle it’s been given. SubProc.p now is removed from the call stack. At this point, and for the duration of MainProc.p, the hProcvariable holds the procedure handle of the running instance of SubProc.p.

You’ll see in the "GET-SIGNATURE method" section how you can make use of this handle.

Now that SubProc.p is in memory, MainProc.p (or any other procedure with access to its handle) can make use of it by running h-UsefulProc1 and h-UsefulProc2 whenever it needs to.

Parameters and persistent procedures

You can pass parameters to a persistent procedure just as you can to any other procedure. If you pass INPUT parameters to it, they are available throughout the life of the persistent procedure. If you pass OUTPUT parameters to it, their values are returned to the caller at the end of the persistent procedure’s instantiation. This is represented in Figure 13–4 by the arrow that returns control to MainProc.p. (Here and elsewhere in this discussion, you should understand that INPUT-OUTPUT parameters have the same characteristics as both INPUT and OUTPUT parameters where this is concerned.)

In practice, you should not normally pass parameters of either kind to a persistent procedure. This is because the best model for using persistent procedures is to initiate them with a RUN statement, and then to access the procedure’s contents afterwards with other statements. This is strictly a matter of programming style—there’s nothing wrong with passing parameters per se. Perhaps the best argument for not doing it is that if you instantiate a persistent procedure simply by running it with no parameters, you maximize the flexibility of how you access it. If it has parameters, then you must always be sure to pass the right parameters when you start it up, which can introduce maintenance problems if the parameter list must change.


Copyright © 2005 Progress Software Corporation
www.progress.com
Voice: (781) 280-4000
Fax: (781) 280-4095